package com.party.mem.web.security;
import com.google.common.base.Function;
import com.party.common.constant.Constant;
import com.party.common.redis.StringJedis;
import com.party.common.utils.LangUtils;
import com.party.common.utils.StringUtils;
import com.party.core.model.member.MemberGroup;
import com.party.core.model.member.XzgsAccountEnum;
import com.party.core.model.system.RoleEnum;
import com.party.core.model.system.SysPrivilege;
import com.party.core.model.system.SysRole;
import com.party.core.service.member.IMemberGroupService;
import com.party.core.service.system.ISysPrivilegeService;
import com.party.core.service.system.ISysRoleService;
import com.party.core.utils.MyBeanUtils;
import com.party.mem.biz.system.member.MemberGroupBizService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;

/**
 * 安全数据源realm
 * party
 * Created by wei.li
 * on 2016/8/26 0026.
 */

@Component(value = "securityRealm")
public class SecurityRealm extends AuthorizingRealm {

    @Autowired
    private ISysRoleService sysRoleService;

    @Autowired
    private ISysPrivilegeService sysPrivilegeService;

    @Autowired
    private IMemberGroupService memberGroupService;
    @Autowired
    private MemberGroupBizService memberGroupBizService;
    @Autowired
    private StringJedis stringJedis;
    protected static Logger logger = LoggerFactory.getLogger(SecurityRealm.class);

    private static String PARTNER_ROLE_CODE = RoleEnum.PARTNER_ROLE.getCode();
    private static String COPARTNER_ROLE_CODE = RoleEnum.COPARTNER_ROLE.getCode();
    private static String XZGS_ADMIN = RoleEnum.XZGS_ADMIN.getCode();
    private static String BRANCH_DIRECTOR = RoleEnum.BRANCH_DIRECTOR.getCode();
    private static String THIRD_MEMBER_ROLE_CODE = "third_member_manager";

    @PostConstruct
    public void initCredentialsMatcher() {
        setCredentialsMatcher(new CustomCredentialsMatcher());
    }

    /**
     * 获取当前用户的权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String loginName = (String) getAvailablePrincipal(principalCollection);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        logger.info("登陆查询");
        MemberGroup member = memberGroupService.get(loginName);

        //角色
        List<SysRole> sysRoles = sysRoleService.findByMemberId(member.getId());
        info.addRoles(sysRoleService.extractCode(sysRoles));

        //资源
        List<String> roleIds = LangUtils.transform(sysRoles, new Function<SysRole, String>() {
            @Override
            public String apply(SysRole sysRole) {
                return sysRole.getId();
            }
        });
        List<SysPrivilege> privilegeList = sysPrivilegeService.findByRoles(new HashSet<>(roleIds));
        info.addStringPermissions(sysPrivilegeService.extractCode(privilegeList));

        return info;
    }

    /**
     * 验证当前登录的Subject
     * @param authenticationToken 登陆凭证
     * @return 授权信息
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取基于用户名和密码的令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        logger.info("查询 member{}", System.currentTimeMillis());
        if (StringUtils.isEmpty(token.getUsername())) {
            return null;
        }
        MemberGroup member = memberGroupService.findByLoginName(token.getUsername(), Constant.MEMBER_ORGANIZATION);
        logger.info("查询 member 结束{}", System.currentTimeMillis());
        if (null != member){

            boolean hasPartner = sysRoleService.hasRole(member.getId(), PARTNER_ROLE_CODE);
            boolean hasThird = sysRoleService.hasRole(member.getId(), THIRD_MEMBER_ROLE_CODE);
            boolean hasCopartner = sysRoleService.hasRole(member.getId(), COPARTNER_ROLE_CODE);
            boolean hasXzgsAdmin = sysRoleService.hasRole(member.getId(), XZGS_ADMIN);
            boolean hasBranchManager = sysRoleService.hasRole(member.getId(), "branchManager");
            if (hasPartner || hasThird || hasCopartner || hasXzgsAdmin) {
                if (!member.getUsername().equals("thirdMemberManage")) {
                    this.removeSession(Constant.THIRD_USER_KEY);
                }

                boolean isChild = memberGroupService.isChild(member.getId());
                CurrentUser currentUser = new CurrentUser();
                try {
                    MyBeanUtils.copyBeanNotNull2Bean(member, currentUser);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                currentUser.setChild(isChild);


                if (hasXzgsAdmin) {
                    currentUser.setChild(true);
                    currentUser.setXzgsAdmin(true);
                    AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member.getId(), member.getPassword(), getName());
                    this.setSession(Constant.CURRENT_USER_KEY, currentUser);
                    return authcInfo;
                } else if (hasBranchManager) {
                    currentUser.setChild(true);
                    currentUser.setOneLevelChildren(false);
                    MemberGroup memberGroup = memberGroupService.get(currentUser.getPartnerId());
                    CurrentUser parentUser = memberGroupBizService.turnIntoCurrentUser(memberGroup);
                    parentUser.setLogo(currentUser.getLogo());
                    parentUser.setRealname(currentUser.getRealname());
                    AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member.getId(), member.getPassword(), getName());
                    this.setSession(Constant.CURRENT_USER_KEY, parentUser);
                    return authcInfo;
                }
                else if (member.getUsername().equals(XzgsAccountEnum.XZGS.getKey())) {
                    currentUser.setChild(false);
                    currentUser.setOneLevelChildren(false);
                    currentUser.setTwoLevelChildren(false);
                    AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member.getId(), member.getPassword(), getName());
                    this.setSession(Constant.CURRENT_USER_KEY, currentUser);
                    return authcInfo;
                }


//                if (isChild) {
//                    // 是否为一级子账号
//                    boolean hasOneLevelRole = sysRoleService.hasRole(member.getId(), RoleEnum.ONE_LEVEL_CHILD.getCode());
//                    currentUser.setOneLevelChildren(hasOneLevelRole);
//
//                    // 是否为二级子账号
//                    boolean hasTwoLevelRole = sysRoleService.hasRole(member.getPartnerId(), RoleEnum.ONE_LEVEL_CHILD.getCode());
//                    currentUser.setTwoLevelChildren(hasTwoLevelRole);
//                } else {
//                    currentUser.setOneLevelChildren(false);
//                    currentUser.setTwoLevelChildren(false);
//                }
//
//                AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(member.getId(), member.getPassword(), getName());
//                this.setSession(Constant.CURRENT_USER_KEY, currentUser);
//                return authcInfo;
            }
        }
        return null;
    }


    /**
     * 将一些数据放到ShiroSession中,以便于其它地方使用
     * 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到
     */
    private void setSession(Object key, Object value) {
        Subject currentUser = SecurityUtils.getSubject();
        if (null != currentUser) {
            Session session = currentUser.getSession();
            if (null != session) {
                session.setAttribute(key, value);
            }
        }
    }

    public void removeSession(Object key) {
        Subject currentUser = SecurityUtils.getSubject();
        if (null != currentUser) {
            Session session = currentUser.getSession();
            if (null != session) {
                session.removeAttribute(key);
            }
        }
    }

    /**
     * 重新赋值权限
     * @param memberId
     */
    public static void reloadAuthorizing(String memberId) {
        logger.info("开始更新用户权限：用户id{}", memberId);
        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        SecurityRealm myRealm = (SecurityRealm) rsm.getRealms().iterator().next();
        Subject subject = SecurityUtils.getSubject();
        String realName = subject.getPrincipals().getRealmNames().iterator().next();
        SimplePrincipalCollection principals = new SimplePrincipalCollection(memberId, realName);
        subject.runAs(principals);
        myRealm.getAuthorizationCache().remove(subject.getPrincipals());
        myRealm.getAuthorizationCache().remove(memberId);
        subject.releaseRunAs();
        logger.info("结束更新用户权限");
    }

}
